{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Object Tracking based on Deep Learning.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_3CcxHNErMI2",
        "colab_type": "text"
      },
      "source": [
        "# **Object Tracking based on Deep Learning**\n",
        "![Fig1](https://i.ibb.co/0JXbPjm/Capture.png)\n",
        "\n",
        "\n",
        "## What is Video tracking?\n",
        "\n",
        "Target tracking is the process of locating moving targets in a video camera for a very wide range of real-world applications. Real-time target tracking is an important task for many computer vision applications, such as surveillance, perception-based user interfaces, augmented reality, object-based video compression and autonomous driving.\n",
        "\n",
        "![Fig2](https://i.ibb.co/KymdPrW/2.png)\n",
        "\n",
        "Historically, there are many ways to track video targets: when you track all moving objects, the difference between the images becomes useful; for tracking the moving hand in the video, the average shift method based on skin color is the best solution; Model matching is a good technique for tracking an aspect of an object.\n",
        "\n",
        "Since the results of the [ImageNet 2012 challenge](http://www.image-net.org/challenges/LSVRC/2012/), Deep Learning (and in particular, Convolutional Neural Networks (CNNs)) has become the main method for solving this kind of problem. Object tracking studies have therefore naturally integrated recognition models, which has made it possible to create tracking algorithms.\n",
        "\n",
        "For more details, you can look at the following projects and tutorials related to the video track challenge:\n",
        "\n",
        "\n",
        "*   [Zero to Hero: A Quick Guide to Object Tracking: MDNET, GOTURN, ROLO\n",
        "](https://cv-tricks.com/object-tracking/quick-guide-mdnet-goturn-rolo/)\n",
        "*   [TRACKING THINGS IN OBJECT DETECTION VIDEOS\n",
        "](https://www.move-lab.com/blog/tracking-things-in-object-detection-videos)\n",
        "\n",
        "*   [Multiple Object Tracking Algorithms\n",
        "](https://medium.com/@manivannan_data/multiple-object-tracking-algorithms-a01973272e52)\n",
        "\n",
        "\n",
        "*   [ImageAI : Video Object Detection, Tracking and Analysis](https://github.com/OlafenwaMoses/ImageAI/blob/master/imageai/Detection/VIDEO.md)\n",
        "\n",
        "*   [Tensorflow Object Tracking Video](https://github.com/DrewNF/Tensorflow_Object_Tracking_Video)\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "Practical books that will allow you to learn the different aspects of video tracking:\n",
        "\n",
        "1.   [Video Tracking: Theory and Practice 1st Edition](https://www.amazon.com/Video-Tracking-Practice-Emilio-Maggio/dp/0470749644)\n",
        "2.   [Video object Tracking: Image Processing and Tracking Paperback – July 16, 2011](https://www.amazon.com/Video-object-Tracking-Image-Processing/dp/3844386238)\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "\n",
        " \n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EGnFpuSL0IqO",
        "colab_type": "text"
      },
      "source": [
        "## Conventional methods for object detection and tracking\n",
        "\n",
        "**1. Basic object detection**\n",
        "\n",
        "To make a baseline movement detection, given the difference between the \"background\" and the other frames, this method is still quite good, but you must first define the background frame, if it is outside, changes in lighting can cause a false detection. Therefore, this method is very limited.\n",
        "OpenCV offers a class, called BackgroundSubtractor, which is useful for splitting the foreground from the background. There are three background separators in OpenCV3: *K-Nearest (KNN)*,* Gaussian Mixture (MOG2)*, and *Geometric Multigid (GMG)*. The BackgroundSubtractor class used for video analysis, i.e. the BackgroundSubtractor class *learns* the context of each image. The BackgroundSubtractor class is often used to compare different frames as well as to record previous frames, which can be used to improve the results of motion analysis.\n",
        "![Img3](https://www.researchgate.net/profile/Venkatesh_Saligrama/publication/224396654/figure/download/fig1/AS:393809457369095@1470902899537/Background-subtraction-results-for-synthetic-objects-moving-against-quasi-static.png)\n",
        "\n",
        "\n",
        "\n",
        "**2. Background splitter by MOG2**\n",
        "\n",
        "One of the basic features of the BackgroundSubtractor class is that it can compute shadows. This is absolutely essential for accurate playback of video images: by detecting shadows, it is possible to exclude shadow areas from the detected image (in threshold mode) so that real attributes can be focused.\n",
        "![image.png]()\n",
        "\n",
        "**3. Background splitter by KNN**\n",
        "\n",
        "The images can be viewed from left to right: detected moving targets, background segmentation, thresholding after background segmentation.\n",
        "![Fig5](https://www.ccoderun.ca/programming/doxygen/opencv/Background_Subtraction_Tutorial_Scheme.png)\n",
        "\n",
        "**4. Kalman object tracking**\n",
        "\n",
        "Kalman is a Hungarian mathematician, who developed a filter from his PhD thesis work and the 1960 [paper](https://asmedigitalcollection.asme.org/fluidsengineering/article/82/1/35/397706/A-New-Approach-to-Linear-Filtering-and-Prediction) entitled \"A New Approach to Linear Filtering and Prediction Problems\".\n",
        "\n",
        "Kalman filtering has been applied in many domains, particularly in the navigation guidance of aircraft and missiles.\n",
        "The Kalman filter works repeatedly on a noisy input data stream (such as a video input in computer vision) and produces a statistically optimal estimate of the state of the underlying system (such as the position in the video).\n",
        "\n",
        "The Kalman filter algorithm is divided into two phases:\n",
        "- Prediction phase: the Kalman filter uses the covariance computed from the current position to estimate the target's new position.\n",
        "- Update phase: the Kalman filter stores the target position and calculates the corrected covariance for the next iteration.\n",
        "\n",
        "![Fig5](https://i.stack.imgur.com/zS2OB.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NVNytefY8qCm",
        "colab_type": "text"
      },
      "source": [
        "## Deep Learning based methods for object detection and tracking\n",
        "\n",
        "In recent years, Deep Learning methods have been successfully applied in the field of object tracking and are gradually exceeding traditional performance methods. In this section, we will present current target tracking algorithms based on Deep Learning.\n",
        "\n",
        "**1. Trends in object tracking**\n",
        "\n",
        "Unlike the trend towards of Deep Learning in the visual domain, such as detection and recognition, the application of this paradigm in the object tracking domain is not seamless. The main problem is the lack of learning data: one of the complications of the deep model comes from the effective learning of a large number of labelled learning data, while target tracking only provides the context for selecting the first image as learning data. In this case, it is difficult to train a deep model from scratch at the beginning of the tracking. Currently, the target tracking algorithm based on Deep Learning takes several ideas to solve this problem, including the following and finally the recurrent neural network in the current tracking field to solve the target tracking problem. Where training data for target tracking is very limited, complementary non-supervised training data is used for pre-training to achieve a high-level feature epresentation of object, and in actual tracking, using the limited sample information from the current tracking target. The accuracy of the pre-training model confers a higher classification performance on the model for the current tracking goal, which significantly reduces the need to track target training samples and improves the performance of the tracking algorithm.\n",
        "\n",
        "**2. Overall multi-target tracking process**\n",
        "\n",
        "In order to track a target, first this target is detected. This step is called *target detection*, then the target in each image is mapped based on the detection result. Today, there are multi-target detectors, such as [SSD](https://arxiv.org/abs/1512.02325) and [YOLO](https://arxiv.org/abs/1506.02640), etc.\n",
        "\n",
        "**3. State-of-the-art methods for object tracking**\n",
        "##### 3.1.GOTURN\n",
        "\n",
        "A further great strength of deep learning is the end-to-end learning process. We believe that this opens up a promising future for tracking. Here is an example of the [*GOTURN* method](https://www.learnopencv.com/goturn-deep-learning-based-object-tracking/). GOTURN's current method has been included in OpenCV 3.2.0 development version.\n",
        "\n",
        "![Fig6](https://www.learnopencv.com/wp-content/uploads/2018/07/goturn-inputs-ouputs-1024x487.jpg)\n",
        "GOTURN involves a convolution network based on the input of a pair of images using the ALOV300+ video sequence set and the ImageNet sensing data set, and generates the position change from the previous frame in the detection area to obtain the target's position on the current frame.\n",
        "\n",
        "##### 3.2. Specific-target tracking\n",
        "\n",
        "In practice, a significant aspect of tracking is the tracking of specific objects, such as face tracking, gesture tracking and human tracking. Tracking a particular object is different from the approach described above and relies more on the training of a particular detector. Due to its obvious features, face tracking is mainly implemented through detection task, such as the state-of-the-art Viola-Jones detection model and the current face detection or face point detection model using Deep learning.\n",
        "\n",
        "##### 3.3. Compression tracking\n",
        "\n",
        "This approach involves using the compressed detection method to represent feature maps, by achieving dimensional reduction and obtaining small-size cues in order to capture large-size feature space (The block diagram is shown in Figure).\n",
        "![Fig7](https://img-blog.csdn.net/20170418162336895?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hmc2h1YWlzaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xUewec8GXEn1",
        "colab_type": "text"
      },
      "source": [
        "## Use case: Motion Tracker\n",
        "Here, we will see how to track the motion of moving objects in the video using OpenCV 3.0 and basic techniques (MOG2). Motion tracking is used to track the motion of objects and then transmit the detected information to an application for further processing.\n",
        "\n",
        "![Fig7](https://i.ytimg.com/vi/XmI2kE2hUgE/maxresdefault.jpg)\n",
        "**Basic dependencies:**\n",
        "\n",
        "- OpenCV 3.0;\n",
        "- Numpy lib.\n",
        "\n",
        "The tracker implementation is as follows:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "l8F889KYUHPQ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "%%writefile points.py\n",
        "import numpy as np\n",
        "import numpy.linalg.linalg as la\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "fst = lambda x: x[0]\n",
        "snd = lambda x: x[1]\n",
        "\n",
        "distance = lambda p1,p2: la.norm(p1 - p2)\n",
        "\n",
        "matchPaths = lambda r, a, paths: [neighborhoodPath(r,paths,ai) for ai in a]\n",
        "\n",
        "neighborhoodPath = lambda r, paths, pnt: [path for path in paths if distance(path[0],pnt) < r]\n",
        "\n",
        "def itemMatcher(choice, items):\n",
        "    items = list(sorted(items, key = lambda x: len(x[1])))\n",
        "    accumulator = []\n",
        "    for index in range(len(items)):\n",
        "        (a, bs) = items[index]\n",
        "        if bs == []:\n",
        "            accumulator.append((a, None))\n",
        "        else:\n",
        "            b = choice(a,bs)\n",
        "            accumulator.append((a, b))\n",
        "            for ind in range(len(items)):\n",
        "                (a2, bs2) = items[ind]\n",
        "                if any(np.array_equal(b,belement) for belement in bs):\n",
        "                    bs2 = [belement for belement in bs2 if not np.array_equal(belement, b)]\n",
        "                items[ind] = (a2, bs2)\n",
        "    return accumulator\n",
        "\n",
        "\n",
        "def extendPaths(r, paths, scatter, filterWith, noisy = False, discard = True):\n",
        "    matches = matchPaths(r,scatter,paths)\n",
        "    zipped = zip(scatter, matches)\n",
        "    def choice(point, pathOptions): \n",
        "        return max(pathOptions,key=len)\n",
        "    def combine(tup):\n",
        "        (pnt, val) = tup\n",
        "        if val == None:\n",
        "            if not noisy:\n",
        "                return [pnt]\n",
        "            else:\n",
        "                return []\n",
        "        else:\n",
        "            return [pnt] + val\n",
        "    lst = itemMatcher(choice, zipped)\n",
        "    extended_paths = map(snd,lst)\n",
        "    if discard:\n",
        "       return filter(lambda x: x != [], map(combine,lst))\n",
        "    unextended_paths = [p for p in paths if not array_in(p,extended_paths)]  \n",
        "    unextended_paths = filter(filterWith, unextended_paths)\n",
        "    return ( unextended_paths, filter(lambda x: x!=[], map(combine, lst)) ) # First element is paths to be archived, second element is the extended paths\n",
        "   \n",
        "\n",
        "def array_in(arr, lst):\n",
        "    return any(np.array_equal(arr,elem) for elem in lst)\n",
        "\n",
        "import pickle\n",
        "def loaddata(filename):\n",
        "    return pickle.load(open(filename))\n",
        "\n",
        "def stringPaths(r, scatters):\n",
        "    paths = []\n",
        "    for sc in scatters:\n",
        "        paths = extendPaths(r, paths, sc)\n",
        "    return paths\n",
        "\n",
        "def plotit(paths):\n",
        "    p = [reduce(lambda x,y: np.append(x,y,axis=0),pa) for pa in paths]\n",
        "    p = map(lambda x: x.T, p)\n",
        "    plt.hold(True)\n",
        "    map(lambda x: plt.plot(x[0],x[1],'x'),p)\n",
        "\n",
        "def shortcut(r, filename):\n",
        "    plotit(stringPaths(r, loaddata(filename)))\n",
        "def rawpoints(filename):\n",
        "    scatters = loaddata(filename)\n",
        "    plotit(scatters)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "b8Vhzbz1R6Or",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "from __future__ import division\n",
        "import numpy as np\n",
        "import cv2\n",
        "import scipy\n",
        "import pickle\n",
        "import points\n",
        "\n",
        "from sys import argv\n",
        "\n",
        "OBJ = True\n",
        "### THE SETTING PARAMETERS FOR VIDEO.MP4\n",
        "if OBJ:\n",
        "    KERN_SIZE = 8\n",
        "    RADIUS = 20\n",
        "    THRESHOLD_AT = 100\n",
        "    INPUT_SIZE_THRESHOLD = 75\n",
        "    MIN_PATH_SIZE = 10\n",
        "    MIN_PATH_STD = 3*RADIUS\n",
        "    WRITE_TO_FILE = True\n",
        "###END PARAMETERS\n",
        "else:\n",
        "    KERN_SIZE = 8\n",
        "    RADIUS = 5\n",
        "    THRESHOLD_AT = 127\n",
        "    INPUT_SIZE_THRESHOLD = 150\n",
        "    MIN_PATH_SIZE = 10\n",
        "    MINI_PATH_STD = 3*RADIUS\n",
        "    WRITE_TO_FILE = True\n",
        "\n",
        "video_output = \"output_tracking.avi\"\n",
        "\n",
        "def avgit(y):\n",
        "    return x.sum(axis=0)/np.shape(y)[0]\n",
        "def plotp(p,mat,color=0):\n",
        "    mat[p[0,1],p[0,0]] = color\n",
        "\n",
        "if len(argv) != 3:\n",
        "    cap = cv2.VideoCapture('vid1.mp4')\n",
        "else:\n",
        "    cap = cv2.VideoCapture(argv[1])\n",
        "    video_outputfile = argv[2]\n",
        "fourcc = cv2.VideoWriter_fourcc(*'XVID')\n",
        "ret, frame = cap.read()\n",
        "height, width, layers = frame.shape\n",
        "video_out = cv2.VideoWriter(video_outputfile, fourcc, 30, (width, height), True)\n",
        "print video_out.isOpened()\n",
        "\n",
        "fgbg = cv2.createBackgroundSubtractorMOG2()\n",
        "bwsub= cv2.createBackgroundSubtractorMOG2()\n",
        "\n",
        "kernlen = KERN_SIZE\n",
        "kern = np.ones((kernlen,kernlen))/(kernlen**2)\n",
        "ddepth = -1\n",
        "def blur(image):\n",
        "    return cv2.filter2D(image,ddepth,kern)\n",
        "def blr_thr(image, val=127):\n",
        "    return cv2.threshold(blur(image),val,255,cv2.THRESH_BINARY)[1]\n",
        "def normalize(image):\n",
        "    s = np.sum(image)\n",
        "    if s == 0:\n",
        "       return image\n",
        "    return height*width* image / s\n",
        "#collection = []\n",
        "paths = []\n",
        "archive = []\n",
        "\n",
        "r = RADIUS\n",
        "thresh_at = THRESHOLD_AT\n",
        "THIS_MUCH_IS_NOISE = INPUT_SIZE_THRESHOLD\n",
        "\n",
        "while(cap.isOpened()):\n",
        "    ret, frame = cap.read()\n",
        "    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
        "    fgmask = fgbg.apply(frame)\n",
        "    mask = blur(fgmask)\n",
        "    ret2, mask = cv2.threshold(mask, thresh_at, 255, cv2.THRESH_BINARY)\n",
        "    \n",
        "    res = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)\n",
        "    cons = res[1]\n",
        "    scatter = map(avgit, cons)\n",
        "    filterWith = lambda x: len(x) > MIN_PATH_SIZE and np.std(x) > MINIMUM_PATH_STD\n",
        "    (toArchive, paths) = points.extendPaths(r, paths, scatter, filterWith, noisy=(len(scatter) > THIS_MUCH_IS_NOISE), discard=False)\n",
        "    archive += toArchive\n",
        "    img = (1 - mask)*gray\n",
        "    for path in archive:\n",
        "        #color = 255\n",
        "        cv2.polylines(img, np.int32([reduce(lambda x,y: np.append(x,y,axis=0), path)]), 0, (255,0,0))\n",
        "    for path in paths:\n",
        "        cv2.polylines(img, np.int32([reduce(lambda x,y: np.append(x,y,axis=0), path)]), 1, (0,0,255))\n",
        "    cv2.imshow('frame', img)\n",
        "    video_out.write(img)\n",
        "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
        "        break\n",
        "cap.release()\n",
        "video_out.release()\n",
        "cv2.destroyAllWindows()\n",
        "\n",
        "\n",
        "if WRITE_TO_FILE:\n",
        "    pickle.dump(archive, open('my_path' + str(np.floor(1000*np.random.rand())) + '.pickle','w'))"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}
